from datetime import datetime, timedelta
from common import config, utils, payments, exceptions
from .base_api import BaseAPI
from db import api as db_api

class LocalAPI(BaseAPI):
    def __init__(self):
        super().__init__()

    def login(self, username, password):
        """用户登录"""
        return db_api.login(username, password)

    def get_home_statistics(self):
        today = datetime.now()
        #获取本日时间范围
        daily_start = today.replace(hour=0, minute=0, second=0, microsecond=0)
        daily_end = today.replace(hour=23, minute=59, second=59)
        #获取本周时间范围
        week_start = (today - timedelta(days=today.weekday())).replace(hour=0, minute=0, second=0, microsecond=0)
        week_end = week_start + timedelta(days=6, hours=23, minutes=59, seconds=59)
        #获取本月时间范围
        month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        if month_start.month == 12:
            next_month = month_start.replace(year=month_start.year+1, month=1)
        else:
            next_month = month_start.replace(month=month_start.month+1)
        month_end = next_month - timedelta(seconds=1)
        month_start_str = month_start.strftime("%Y-%m-%d %H:%M:%S")
        month_end_str = month_end.strftime("%Y-%m-%d %H:%M:%S")
        #获取本年时间范围
        year_start = today.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
        year_end = today.replace(month=12, day=31, hour=23, minute=59, second=59)
        
        # 头部卡片数据
        total_products = db_api.get_count("products", {})
        low_stock_products = db_api.get_count("products", {"stock <= lowest_stock": ""})
        daily_sales = db_api.get_count("sales", {"created_at": [daily_start, daily_end]})
        monthly_sales = db_api.get_count("sales", {"created_at": [month_start_str, month_end_str]})
        daily_sales_prices = db_api.get_total_price("sales", {"created_at": [daily_start, daily_end]})
        monthly_sales_prices = db_api.get_total_price("sales", {"created_at": [month_start_str, month_end_str]})
        daily_sales_return = db_api.get_count("sale_returns", {"created_at": [daily_start, daily_end]})
        monthly_sales_return = db_api.get_count("sale_returns", {"created_at": [month_start_str, month_end_str]})
        daily_sales_prices_return = db_api.get_total_price("sale_returns", {"created_at": [daily_start, daily_end]})
        monthly_sales_prices_return = db_api.get_total_price("sale_returns", {"created_at": [month_start_str, month_end_str]})
            
        return {"total_products": total_products, "low_stock_products": low_stock_products,
                "daily_sales": daily_sales, "daily_sales_prices": daily_sales_prices,
                "monthly_sales": monthly_sales, "monthly_sales_prices": monthly_sales_prices,
                "daily_sales_return": daily_sales_return, "daily_sales_prices_return": daily_sales_prices_return,
                "monthly_sales_return": monthly_sales_return, "monthly_sales_prices_return": monthly_sales_prices_return}
    
    def get_sales_chart_data(self, range_date="week"):
        if range_date not in ["week", "month", "year"]:
            raise exceptions.ErrorException("时间段只能选择'week', 'month'或'year'.")
        chart_data = db_api.get_sales_chart_data(range_date)
        parsed_data = []
        today = datetime.now()
        if range_date == "week":
            week_start = (today - timedelta(days=today.weekday())).replace(hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.weekday() + 1):
                date = week_start + timedelta(days=i)
                date_str = date.day
                if date_str in chart_data:
                    parsed_data.append({utils.WEEKDAYS[i]: chart_data[date_str]})
                else:
                    parsed_data.append({utils.WEEKDAYS[i]: 0})
        elif range_date == "month":
            month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.day + 1):
                date = month_start.replace(day=i)
                date_str = date.day
                if date_str in chart_data:
                    parsed_data.append({f"{i}日": chart_data[date_str]})
                else:
                    parsed_data.append({f"{i}日": 0})
        else:
            year_start = today.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.month + 1):
                date = year_start.replace(month=i)
                date_str = date.month
                if date_str in chart_data:
                    parsed_data.append({f"{i}月": chart_data[date_str]})
                else:
                    parsed_data.append({f"{i}月": 0})
        return parsed_data
    
    def get_purchases_chart_data(self, range_date="week"):
        if range_date not in ["week", "month", "year"]:
            raise exceptions.ErrorException("时间段只能选择'week', 'month'或'year'.")
        chart_data = db_api.get_purchases_chart_data(range_date)
        parsed_data = []
        today = datetime.now()
        if range_date == "week":
            week_start = (today - timedelta(days=today.weekday())).replace(hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.weekday() + 1):
                date = week_start + timedelta(days=i)
                date_str = date.day
                if date_str in chart_data:
                    parsed_data.append({utils.WEEKDAYS[i]: chart_data[date_str]})
                else:
                    parsed_data.append({utils.WEEKDAYS[i]: 0})
        elif range_date == "month":
            month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.day + 1):
                date = month_start.replace(day=i)
                date_str = date.day
                if date_str in chart_data:
                    parsed_data.append({f"{i}日": chart_data[date_str]})
                else:
                    parsed_data.append({f"{i}日": 0})
        else:
            year_start = today.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.month + 1):
                date = year_start.replace(month=i)
                date_str = date.month
                if date_str in chart_data:
                    parsed_data.append({f"{i}月": chart_data[date_str]})
                else:
                    parsed_data.append({f"{i}月": 0})
        return parsed_data
    
    def get_sales_return_chart_data(self, range_date="week"):
        if range_date not in ["week", "month", "year"]:
            raise exceptions.ErrorException("时间段只能选择'week', 'month'或'year'.")
        chart_data = db_api.get_sales_return_chart_data(range_date)
        parsed_data = []
        today = datetime.now()
        if range_date == "week":
            week_start = (today - timedelta(days=today.weekday())).replace(hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.weekday() + 1):
                date = week_start + timedelta(days=i)
                date_str = date.day
                if date_str in chart_data:
                    parsed_data.append({utils.WEEKDAYS[i]: chart_data[date_str]})
                else:
                    parsed_data.append({utils.WEEKDAYS[i]: 0})
        elif range_date == "month":
            month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.day + 1):
                date = month_start.replace(day=i)
                date_str = date.day
                if date_str in chart_data:
                    parsed_data.append({f"{i}日": chart_data[date_str]})
                else:
                    parsed_data.append({f"{i}日": 0})
        else:
            year_start = today.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
            for i in range(1, today.month + 1):
                date = year_start.replace(month=i)
                date_str = date.month
                if date_str in chart_data:
                    parsed_data.append({f"{i}月": chart_data[date_str]})
                else:
                    parsed_data.append({f"{i}月": 0})
        return parsed_data
    
    def get_hot_products_chart_data(self, range_date='week', count=config.TOP_SALE_PRODUCT_COUNT):
        now = datetime.now()
        if range_date == "week":
            start_date = now.replace(hour=0, minute=0, second=0) - timedelta(days=now.weekday())
            end_date = now.replace(hour=23, minute=59, second=59)
        elif range_date == "month":
            start_date = now.replace(day=1, hour=0, minute=0, second=0)
            if now.month == 12:
                end_date = now.replace(year=now.year + 1, month=1, day=1, hour=0, minute=0, second=0) - timedelta(seconds=1)
            else:
                end_date = now.replace(month=now.month + 1, day=1, hour=0, minute=0, second=0) - timedelta(seconds=1)
        elif range_date == "year":
            start_date = now.replace(month=1, day=1, hour=0, minute=0, second=0)
            end_date = now.replace(month=12, day=31, hour=23, minute=59, second=59)
        else:
            raise exceptions.ErrorException("时间段只能选择'week', 'month'或'year'.")
        chart_data = db_api.calculate_top_profit_products(start_date, end_date, None, count)
        parsed_data = []
        for product in chart_data:
            parsed_data.append({product["product_name"]: (product["sales_total"], product["profit_total"])})
        return parsed_data

    def get_suppliers(self, search, page=1, per_page=config.DEFAULT_PAGE_SIZE):
        if search.isdigit() and len(search) > 4: #手机号必须大于4位数才可以搜索
            name_or_contact = None
            phone = search
        elif len(search) > 1:   #非数字都为联系人搜索
            name_or_contact = search
            phone = None
        else:
            name_or_contact = None
            phone = None
        return db_api.get_suppliers(name_or_contact, phone, page, per_page)

    def get_users(self, username="", role="", status=None, page=1, per_page=config.DEFAULT_PAGE_SIZE):
        status = utils.string_to_bool(status, True)
        return db_api.get_users(username, role, status, page, per_page)
    
    def add_user(self, username, password, role, status=True):
        status = utils.string_to_bool(status, True)
        return db_api.add_user(username, password, role, status)
        
    def get_user(self, user_id):
        return db_api.get_user(user_id)
    
    def update_user(self, user_id, username="", password="", role="", status=None):
        status = utils.string_to_bool(status, True)
        return db_api.update_user(user_id, username, password, role, status)
    
    def delete_user(self, user_id):
        return db_api.delete_user(user_id)
    
    # 产品相关方法
    def get_products(self, search, category_id=None, status=None, low_stock_only=False, page=1, per_page=config.DEFAULT_PAGE_SIZE, order_by=""):
        status = utils.string_to_bool(status, True)
        search = search.lower()
        if not search:
            code = None
            name = None
        elif utils.match_product_code(search) or (search.isdigit() and len(search) > 4):
            code = search
            name = None
        else:
            code = None
            name = search
        return db_api.get_products(code, name, category_id, status, low_stock_only, page, per_page, order_by)
    
    def get_product(self, id_or_code):
        return db_api.get_product(id_or_code)
    
    def add_product(self, name, category_id, unit, price, stock, lowest_stock=0, description="", status=True):
        return db_api.add_product(name, category_id, unit, price, stock, lowest_stock, description, status)
    
    def update_product(self, code, name = None, category_id = None, unit = None, price="", lowest_stock="", description="", status=None):
        status = utils.string_to_bool(status, True)
        return db_api.update_product(code, name, category_id, unit, price, lowest_stock, description, status)
    
    def delete_product(self, code):
        return db_api.delete_product(code)
    
    # 分类相关方法
    def get_categories(self, parent_id=None):
        return db_api.get_categories(parent_id)
    
    def get_category(self, id):
        return db_api.get_category(id)
    
    def add_category(self, name, parent_id=None):
        return db_api.add_category(name, parent_id)
    
    def delete_category(self, category_id):
        return db_api.delete_category(category_id)
    
    # 供应商相关方法
    def get_supplier(self, supplier_id):
        return db_api.get_supplier(supplier_id)
    
    def get_all_suppliers(self):
        suppliers = db_api.get_suppliers(None, None, 0, 0)
        if not suppliers:
            return []
        return suppliers["items"]
    
    def add_supplier(self, name, contact, phone, wechat="", address=""):
        return db_api.add_supplier(name, contact, phone, wechat, address)
    
    def update_supplier(self, supplier_id, name, contact, phone, wechat="", address=""):
        return db_api.update_supplier(supplier_id, name, contact, phone, wechat, address)
    
    def delete_supplier(self, supplier_id):
        return db_api.delete_supplier(supplier_id)
    
    # 销售相关方法
    def get_sales(self, code="", product_id=None, customer_id=None, status=None, user_id=None, page=1, per_page=config.DEFAULT_PAGE_SIZE,
                  order_by="", range_date=None):
        return db_api.get_sales(code, product_id, customer_id, status, user_id, page, per_page, order_by, range_date)
    
    def get_sale(self, id_or_code):
        return db_api.get_sale(id_or_code)
    
    def get_sale_returns(self, sale_id_or_code):
        return db_api.get_sale_returns(sale_id_or_code)
    
    def add_sale_return(self, sale_code_or_id, user_id, items, reason="", return_date=datetime.now()):
        return db_api.add_sale_return(sale_code_or_id, user_id, items, reason, return_date)
    
    def add_sale(self, customer_id, user_id, items):
        return db_api.add_sale(customer_id, user_id, items)
    
    def update_sale(self, id_or_code, status=None):
        return db_api.update_sale(id_or_code, status)
    
    def update_sale_items(self, id_or_code, items):
        return db_api.update_sale_items(id_or_code, items)
    
    def delete_sale(self, code):
        return db_api.delete_sale(code)
    
    # 采购相关方法
    def get_purchases(self, code="", supplier_id=None, status=None, product_id=None, page=1, per_page=config.DEFAULT_PAGE_SIZE,
                      order_by="", range_date=None):
        return db_api.get_purchases(code, supplier_id, status, product_id, page, per_page, order_by, range_date)
    
    def get_purchase(self, id_or_code):
        return db_api.get_purchase(id_or_code)
    
    def add_purchase(self, supplier_id, user_id, items):
        return db_api.add_purchase(supplier_id, user_id, items)
    
    def update_purchase(self, code, status=None):
        return db_api.update_purchase(code, status)
    
    def update_purchase_items(self, code, items):
        return db_api.update_purchase_items(code, items)
    
    def delete_purchase(self, code):
        return db_api.delete_purchase(code)
    
    def add_purchase_return(self, purchase_code_or_id, user_id, items, reason="", return_date=datetime.now()):
        return db_api.add_purchase_return(purchase_code_or_id, user_id, items, reason, return_date)
    
    def get_purchase_returns(self, purchase_id_or_code):
        return db_api.get_purchase_returns(purchase_id_or_code)
    
    def get_customers(self, search="", extras=False, page=1, per_page=config.DEFAULT_PAGE_SIZE):
        if search:
            if utils.match_phone_number(search) or (search.isdigit() and len(search) >= 4):
                contact = None
                phone = search
            else:
                contact = search
                phone = None
        else:
            contact = None
            phone = None
        return db_api.get_customers(contact, phone, extras, page, per_page)
    
    def get_customer(self, id):
        return db_api.get_customer(id)
    
    def add_customer(self, contact, phone, wechat=""):
        return db_api.add_customer(contact, phone, wechat)
    
    def update_customer(self, customer_id, contact, phone, wechat=""):
        return db_api.update_customer(customer_id, contact, phone, wechat)
    
    def delete_customer(self, customer_id):
        return db_api.delete_customer(customer_id)
    
    def get_supplier_products(self, supplier_id):
        return db_api.get_supplier_products(supplier_id)
    
    def update_supplier_products(self, supplier_id, products):
        return db_api.update_supplier_products(supplier_id, products)
    
    def get_product_suppliers(self, product_id):
        return db_api.get_product_suppliers(product_id)
    
    def generate_supplier_low_stock_products(self, supplier_id):
        supplier_products = db_api.get_supplier_products(supplier_id)
        products = []
        for product in supplier_products:
            product_info = product["product"]
            if product_info["stock"] <= product_info["lowest_stock"]:
                product_info["cost_price"] = product["cost_price"]
                products.append(product_info)
        return products

    def get_supplier_products_by_search(self, supplier_id, search):
        if not search or (search.isdigit() and len(search) <= 4):
            return []
        return db_api.search_supplier_products(supplier_id, search)
    
    def pay_sale(self, sale_id, payment_method, auth_code=''):
        # TODO: 支付失败记录
        if payment_method == utils.PaymentMethod.CASH:
            return self.update_sale(sale_id, utils.SaleStatus.PAID, payment_method)
        elif payment_method == utils.PaymentMethod.WECHAT:
            result = payments.WeChatMicropay(sale_id).pay(auth_code)
            if result["return_code"] == "SUCCESS" and result["result_code"] == "SUCCESS":
                self.update_sale(sale_id, utils.SaleStatus.PAID, payment_method)
                return True
        elif payment_method == utils.PaymentMethod.ALIPAY:
            result = payments.AlipayMicropay(sale_id).pay(auth_code)
            if result.get("code") == "10000" and result.get("trade_status") == "TRADE_SUCCESS":
                self.update_sale(sale_id, utils.SaleStatus.PAID, payment_method)
                return True
        return False
    
    # 日志相关方法
    def get_logs(self, dateOrRange=None, page=1, per_page=config.DEFAULT_PAGE_SIZE):
        return db_api.get_logs(dateOrRange, page, per_page)
    
    def add_log(self, user_id, details, relations={}):
        return db_api.add_log(user_id, details, relations)
    